package protoredis

import (
	"fmt"
	"strconv"
	"strings"
	"sync/atomic"
	"time"

	"gitee.com/crack007/proxy/src/proxy/protocol/logdump"

	"gitee.com/crack007/proxy/src/config"

	"gitee.com/crack007/goose/gscore/server"
)

var redisId int64

type Redis struct {
	sessionId    string
	Session      *server.Session
	queryStartAt time.Time
	redisFullCmd string
	db           int
	proto        *ClientProtocol
	Exclude      map[string]bool // 排除掉的 redis 指令。
}

func (r *Redis) ProcessClient(data []byte) {
	// 处理分包的问题
	if r.proto == nil {
		r.proto = NewClientProtocol()
	}
	r.proto.AppendData(data)
	if !r.proto.IsFull() {
		return
	}
	r.redisFullCmd = r.proto.GetFullCmd()
	defer func() {
		r.proto = nil
	}()
	if _, ok := r.Exclude[r.proto.GetCmd()]; ok {
		return
	}
	r.queryStartAt = time.Now()
	if strings.ToUpper(r.proto.GetCmd()) == "SELECT" {
		db := strings.ReplaceAll(strings.ToUpper(r.redisFullCmd), "SELECT", "")
		r.db, _ = strconv.Atoi(strings.TrimSpace(db))
		logdump.Warn(fmt.Sprintf("[%s][db:%d] %s", r.GetSessionId(), r.db, r.redisFullCmd))
		return
	}
	logdump.Info(fmt.Sprintf("[%s][db:%d] %s", r.GetSessionId(), r.db, r.redisFullCmd))
}

func (r *Redis) GetSessionId() string {
	return r.sessionId
}

func (r *Redis) ProcessServer(serverSession *server.Client, data []byte) {
	if r.queryStartAt.IsZero() {
		return
	}
	costTime := time.Since(r.queryStartAt)
	if config.RedisConfig.Slow > 0 && int(costTime.Milliseconds()) > config.RedisConfig.Slow {
		logdump.Warn("[%s][%d][%s][SLOW] %s", r.GetSessionId(), r.db, costTime.String(), r.redisFullCmd)
		return
	}
}

func (r *Redis) Init(session *server.Session) {
	r.Session = session
	r.sessionId = strconv.Itoa(int(atomic.AddInt64(&redisId, 1)))
	if config.RedisConfig.Exclude != "" {
		list := strings.Split(config.RedisConfig.Exclude, ",")
		for _, v := range list {
			r.Exclude[strings.ToUpper(v)] = true
		}
	}
}
